package com.hzw.saas.service.hpc.service.impl;


import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.hpc.IHpcAccountDetailService;
import com.hzw.saas.api.hpc.IHpcAccountIncreaseService;
import com.hzw.saas.api.hpc.IHpcAccountRecordService;
import com.hzw.saas.api.hpc.IHpcAccountUserService;
import com.hzw.saas.api.hpc.bo.*;
import com.hzw.saas.common.util.Arith;
import com.hzw.saas.common.util.LocalDateTimeUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.hpc.mapper.HpcAccountAmountDailyMapper;
import com.hzw.saas.service.hpc.mapper.HpcAccountIncreaseMapper;
import com.hzw.saas.service.hpc.mapper.HpcAccountRecordMapper;
import com.hzw.saas.service.hpc.model.HpcAccountAmountDaily;
import com.hzw.saas.service.hpc.model.HpcAccountIncrease;
import com.hzw.saas.service.hpc.model.HpcAccountRecord;
import com.hzw.saas.service.hpc.util.BeanUtil;
import com.hzw.saas.service.hpc.util.BigDecimalUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("hpcAccountIncreaseImpl")
@RequiredArgsConstructor
public class HpcAccountIncreaseImpl extends ServiceImpl<HpcAccountIncreaseMapper, HpcAccountIncrease>  implements IHpcAccountIncreaseService, IService<HpcAccountIncrease> {

    @Resource(name = "hpcAccountRecordServiceImpl")
    private IHpcAccountRecordService hpcAccountRecordService;
    @Resource(name = "hpcAccountUserServiceImpl")
    private IHpcAccountUserService hpcAccountUserService;
    @Resource(name = "hpcAccountDetailServiceImpl")
    private IHpcAccountDetailService hpcAccountDetailService;

    private final HpcAccountAmountDailyMapper hpcAccountAmountDailyMapper;
    private final HpcAccountRecordMapper hpcAccountRecordMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void powerIncrease() {
        //冻结全部过期账号
        hpcAccountUserService.frozenAll();
        //查询所有需要被增值的record_id
        List<UserAndAccountBo> needIncrease = hpcAccountRecordService.findNeedIncrease();
        //实际金额
        HashMap<String, BigDecimal> stringBigDecimalHashMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(needIncrease)){
            List<String> stringList = needIncrease.stream().map(UserAndAccountBo::getPid).collect(Collectors.toList());
            //查询所有历史利息
            ArrayList<UserAndAccountBo> userAndAccountBos = new ArrayList<>();
            Map<String, List<BigDecimal>> increaseHistoryByRecordIds = findIncreaseHistoryByRecordIds(stringList);
            increaseHistoryByRecordIds.forEach((s,bs)->{
                needIncrease.forEach(userAndAccountBo -> {
                    if (s.equals(userAndAccountBo.getPid()) ){
                        BigDecimal bigDecimal = BigDecimalUtil.moneyAdd(userAndAccountBo.getCoreTimeBalance(), bs.stream().reduce(BigDecimal.ZERO, BigDecimal::add));
                        if (BigDecimalUtil.moneyCompTh(bigDecimal,BigDecimal.ZERO)){
                            stringBigDecimalHashMap.put(s,bigDecimal);
                        }
                        //移除加入map里的数据
                        userAndAccountBos.add(userAndAccountBo);
                    }
                });
            });
            needIncrease.removeAll(userAndAccountBos);
            //没有历史记录第一次有利息
            if (CollectionUtils.isNotEmpty(needIncrease)){
                needIncrease.forEach(userAndAccountBo -> {
                    if(BigDecimalUtil.moneyCompTh(userAndAccountBo.getCoreTimeBalance(),BigDecimal.ZERO)){
                        stringBigDecimalHashMap.put(userAndAccountBo.getPid(),userAndAccountBo.getCoreTimeBalance());
                    }
                });
            }
            //至此需要增值的数据的实际金额全部计算完毕
            if(!stringBigDecimalHashMap.isEmpty()) {
                saveIncrease(stringBigDecimalHashMap);
            }
        }
    }

    private void saveIncrease(Map<String,BigDecimal> map){
        ArrayList<HpcAccountIncrease> hpcAccountIncreases = new ArrayList<>();
        map.forEach((s,b)->{
            HpcAccountIncrease hpcAccountIncrease = new HpcAccountIncrease();
            hpcAccountIncrease.setAccountRecordPid(s);
            hpcAccountIncrease.setPid(SnowFlakeUtil.nextId().toString());
            hpcAccountIncrease.setCountBeforeIncrease(b);
            hpcAccountIncrease.setSingleCount(powerCount(b));
            hpcAccountIncrease.setAnnualizedInterestRate(getInterestRate());
            hpcAccountIncrease.setIsDelete(0);
            hpcAccountIncrease.setCreateTime(LocalDateTime.now());
            hpcAccountIncrease.setUpdateTime(LocalDateTime.now());
            hpcAccountIncrease.setSubTableFiled(1L);
            hpcAccountIncrease.setSubTreasuryFiled(1L);
            hpcAccountIncrease.setIncreaseDate(LocalDateTimeUtils.minu(LocalDateTime.now(),1L, ChronoUnit.DAYS));
            hpcAccountIncreases.add(hpcAccountIncrease);

        });
        saveBatch(hpcAccountIncreases);
    }

    //根据id查询所有的增值历史
    @Override
    public Map<String,List<BigDecimal>> findIncreaseHistoryByRecordIds(List<String> ids){
        List<HpcAccountIncrease> list = this.lambdaQuery().in(HpcAccountIncrease::getAccountRecordPid, ids)
            .eq(HpcAccountIncrease::getIsDelete, 0)
            .list();
        Map<String, List<HpcAccountIncrease>> collect = list.stream().collect(Collectors.groupingBy(HpcAccountIncrease::getAccountRecordPid));
        HashMap<String, List<BigDecimal>> stringListHashMap = new HashMap<>();
        collect.forEach((s, hpcAccountIncreases) -> {
            stringListHashMap.put(s,hpcAccountIncreases.stream().map(HpcAccountIncrease::getSingleCount).collect(Collectors.toList()));
        });

        return stringListHashMap;
    }

    @Transactional
    void deleteIncreaseHistoryByRecordIds(List<String> accountIds) {
        List<HpcAccountIncrease> list = this.lambdaQuery().in(HpcAccountIncrease::getAccountRecordPid, accountIds).list();
        removeByIds(list);
    }

    @Override
    public List<String> findAlreadyIncreased() {
        //查询所有今天有数据且利息不为空的
        List<HpcAccountIncrease> list = this.lambdaQuery()
            .ge(HpcAccountIncrease::getCreateTime, LocalDate.now() + " 00::00::00")
            .isNotNull(HpcAccountIncrease::getSingleCount)
            .or()
            .eq(HpcAccountIncrease::getSingleCount,BigDecimal.ZERO)
            .list();
        return list.stream().map(HpcAccountIncrease::getAccountRecordPid).collect(Collectors.toList());
    }

    @Override
    public BigDecimal getInterestRate() {
        return new BigDecimal("0.02");
    }

    @Override
    public BigDecimal powerCount(BigDecimal nowPower) {
        BigDecimal interestRate = getInterestRate();
        BigDecimal moneyDiv = BigDecimalUtil.moneydiv(interestRate, new BigDecimal("365"), 10);
        return BigDecimalUtil.moneyMul(moneyDiv,nowPower);

    }

    @Override
    public List<HpcAccountIncreaseBo> findIncrease(List<String> accountRecordId) {
        if(CollectionUtils.isEmpty(accountRecordId)) return new ArrayList<>();
        List<HpcAccountIncrease> list = this.lambdaQuery()
            .in(HpcAccountIncrease::getAccountRecordPid, accountRecordId)
            .orderByAsc(HpcAccountIncrease::getIncreaseDate).list();
        return BeanUtil.copyListProperties(list, HpcAccountIncreaseBo.class);
    }

    private HpcAccountIncrease powerIncreaseById(String recordPid, BigDecimal singleCount, LocalDateTime date) {
        HpcAccountIncrease hpcAccountIncrease = new HpcAccountIncrease();
        hpcAccountIncrease.setAccountRecordPid(recordPid);
        hpcAccountIncrease.setPid(SnowFlakeUtil.nextId().toString());
        hpcAccountIncrease.setSingleCount(singleCount);
        hpcAccountIncrease.setAnnualizedInterestRate(getInterestRate());
        hpcAccountIncrease.setIsDelete(0);
        hpcAccountIncrease.setCreateTime(LocalDateTime.now());
        hpcAccountIncrease.setUpdateTime(LocalDateTime.now());
        hpcAccountIncrease.setSubTableFiled(1L);
        hpcAccountIncrease.setSubTreasuryFiled(1L);
        hpcAccountIncrease.setIncreaseDate(date);
        return hpcAccountIncrease;
    }

    private HpcPowerCountDTO emptyHpcPowerCountDTO(){
        HpcPowerCountDTO hpcPowerCountDTO = new HpcPowerCountDTO();
        hpcPowerCountDTO.setAccountBalance(BigDecimal.ZERO);
        hpcPowerCountDTO.setAllProfit(BigDecimal.ZERO);
        hpcPowerCountDTO.setLastProfit(BigDecimal.ZERO);
        hpcPowerCountDTO.setAnnualizedInterestRate(getInterestRate());
        hpcPowerCountDTO.setAccountBalanceTotal(BigDecimal.ZERO);
        hpcPowerCountDTO.setConsumptionToday(BigDecimal.ZERO);
        hpcPowerCountDTO.setAccountBalanceTotal(BigDecimal.ZERO);
        return hpcPowerCountDTO;
    }

    @Override
    public HpcPowerCountDTO findHpcPowerCountDTO(List<String> hpcAccountUserIds) {
        HpcPowerCountDTO hpcPowerCountDTO = emptyHpcPowerCountDTO();
        if (hpcAccountUserIds.isEmpty()){
           return hpcPowerCountDTO;
        }

        // 获取可用的HPC账号列表，不包含过期的账号
        List<HpcAccountUserBo> hpcAccountUserList = hpcAccountUserService.getUsableHpcAccountUserList(hpcAccountUserIds);
        if(CollectionUtils.isEmpty(hpcAccountUserList)) {
            return hpcPowerCountDTO;
        }
        List<String> accountRecordIds = hpcAccountUserList.stream().map(HpcAccountUserBo::getHpcAccountRecordId).collect(Collectors.toList());

        // 获取今日消耗
        Double consumptionToday = hpcAccountDetailService.getHpcCoreSumByScopeDate(accountRecordIds, new Date(), new Date());
        hpcPowerCountDTO.setConsumptionToday(NumberUtil.round(consumptionToday, 2));

        // 获取recordIds对应的余额
        BigDecimal sumCoreTimeBalance = BigDecimal.valueOf(hpcAccountUserList.stream().mapToDouble(HpcAccountUserBo::getCoreTimeBalance).sum());
        hpcPowerCountDTO.setAccountBalance(sumCoreTimeBalance.setScale(2, BigDecimal.ROUND_HALF_UP));

        // 获取recordIds对应的核时总量
        BigDecimal sumCoreTimeBalanceTotal = BigDecimal.valueOf(hpcAccountUserList.stream().mapToDouble(HpcAccountUserBo::getCoreTimeBalanceTotal).sum());
        hpcPowerCountDTO.setAccountBalanceTotal(sumCoreTimeBalanceTotal.setScale(2, BigDecimal.ROUND_HALF_UP));

        // 查询增值信息
        List<HpcAccountIncrease> hpcAccountIncreaseList = this.lambdaQuery().in(HpcAccountIncrease::getAccountRecordPid, accountRecordIds)
            .orderByDesc(HpcAccountIncrease::getCreateTime).list();
        Map<String, List<HpcAccountIncrease>> hpcAccountIncreasesMap = hpcAccountIncreaseList.stream().collect(Collectors.groupingBy(HpcAccountIncrease::getAccountRecordPid));

        if (!CollectionUtils.isEmpty(hpcAccountIncreasesMap)){
            ArrayList<HpcPowerCountDTO> hpcPowerCountDTOS = new ArrayList<>();
            hpcAccountIncreasesMap.forEach((recordId, hpcAccountIncreases)->{
                HpcPowerCountDTO hpcPowerCountDTO1 = new HpcPowerCountDTO();
                HpcAccountIncrease hpcAccountIncrease = hpcAccountIncreases.get(0);
                hpcPowerCountDTO1.setLastProfit(BigDecimal.ZERO);
                LocalDate localDate = hpcAccountIncrease.getIncreaseDate().toLocalDate();
                LocalDate now = LocalDate.now();

                if (LocalDateTimeUtils.betweenTwoTime(localDate, now, ChronoUnit.DAYS) == 1L){
                    hpcPowerCountDTO1.setLastProfit(hpcAccountIncreases.get(0).getSingleCount());
                }

                List<BigDecimal> collect = hpcAccountIncreases.stream().map(HpcAccountIncrease::getSingleCount).collect(Collectors.toList());
                hpcPowerCountDTO1.setAllProfit(collect.stream().reduce(BigDecimal.ZERO,BigDecimal::add));
                hpcPowerCountDTO1.setAnnualizedInterestRate(hpcAccountIncreases.get(0).getAnnualizedInterestRate());

                hpcPowerCountDTOS.add(hpcPowerCountDTO1);
            });

            if(CollectionUtils.isNotEmpty(hpcPowerCountDTOS)) {
                // 计算昨日收益
                BigDecimal reduceLastProfit = hpcPowerCountDTOS.stream().map(HpcPowerCountDTO::getLastProfit).reduce(BigDecimal.ZERO, BigDecimal::add);
                hpcPowerCountDTO.setLastProfit(reduceLastProfit.setScale(2, BigDecimal.ROUND_HALF_UP));
                // 计算累计收益
                BigDecimal reduceAllProfit = hpcPowerCountDTOS.stream().map(HpcPowerCountDTO::getAllProfit).reduce(BigDecimal.ZERO, BigDecimal::add);
                hpcPowerCountDTO.setAllProfit(reduceAllProfit.setScale(2, BigDecimal.ROUND_HALF_UP));
                // 获取利率
                hpcPowerCountDTO.setAnnualizedInterestRate(hpcPowerCountDTOS.get(0).getAnnualizedInterestRate().setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            // 设置算力总额 = 算力余额 + 累计收益
            hpcPowerCountDTO.setAccountBalanceTotal(hpcPowerCountDTO.getAccountBalance().add(hpcPowerCountDTO.getAllProfit()).setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        return hpcPowerCountDTO;
    }

    @Override
    public double getSumIncreaseByStartDate(List<String> hpcAccountRecordIds, Date startDate) {
        if(CollectionUtils.isEmpty(hpcAccountRecordIds)) return 0;

        QueryWrapper<HpcAccountIncrease> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("IFNULL(sum(single_count),0) as singleCount").
            lambda()
            .in(HpcAccountIncrease::getAccountRecordPid, hpcAccountRecordIds)
            .le(HpcAccountIncrease::getIncreaseDate, startDate);
        HpcAccountIncrease hpcAccountIncrease = this.getOne(queryWrapper);

        return hpcAccountIncrease.getSingleCount().doubleValue();
    }

    @Override
    public void powerIncrease(String hpcAccountRecordId) {
        HpcAccountRecord hpcAccountRecord = hpcAccountRecordMapper.getHpcAccountRecordByPid(hpcAccountRecordId);
        powerIncrease(MapperUtil.nf().map(hpcAccountRecord, HpcAccountRecordBo.class));
    }

    @Override
    public void powerIncrease(HpcAccountRecordBo hpcAccountRecordBo) {
        if(Objects.isNull(hpcAccountRecordBo)) {
            return;
        }

        String hpcAccountRecordId = hpcAccountRecordBo.getPid();
        List<HpcAccountAmountDaily> hpcAccountAmountDailies = hpcAccountAmountDailyMapper.selectList(Wrappers.<HpcAccountAmountDaily>lambdaQuery()
            .eq(HpcAccountAmountDaily::getHpcAccountRecordId, hpcAccountRecordId)
            .orderByAsc(HpcAccountAmountDaily::getBusTime));
        if(CollectionUtils.isEmpty(hpcAccountAmountDailies)) {
            return;
        }

        List<HpcAccountIncrease> hpcAccountIncreases = new ArrayList<>();
        for(int i = 0; i < hpcAccountAmountDailies.size(); i ++) {
            HpcAccountAmountDaily hpcAccountAmountDaily = hpcAccountAmountDailies.get(i);

            HpcAccountIncrease hpcAccountIncrease = new HpcAccountIncrease();
            hpcAccountIncrease.setAccountRecordPid(hpcAccountRecordId);
            hpcAccountIncrease.setAnnualizedInterestRate(getInterestRate());
            hpcAccountIncrease.setSubTableFiled(1L);
            hpcAccountIncrease.setSubTreasuryFiled(1L);
            hpcAccountIncrease.setIncreaseDate(LocalDateTimeUtil.of(hpcAccountAmountDaily.getBusTime()));
            hpcAccountIncrease.setPid(SnowFlakeUtil.nextIdStr());

            BigDecimal moneyDiv = BigDecimalUtil.moneydiv(getInterestRate(), new BigDecimal("365"), 10);
            // 当前用户余额
            Double curCoreTimeBalance = hpcAccountAmountDaily.getCurCoreTimeBalance();
            // 计算增值数据
            BigDecimal oldIncreaseSum = hpcAccountIncreases.stream().map(HpcAccountIncrease::getSingleCount).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add));
            Double increasesCoreTimeBalance = Arith.mul(Arith.add(curCoreTimeBalance, oldIncreaseSum.doubleValue()), moneyDiv.doubleValue());
            hpcAccountIncrease.setSingleCount(BigDecimal.valueOf(increasesCoreTimeBalance)); // 增值算力
            hpcAccountIncrease.setCountBeforeIncrease(BigDecimal.valueOf(Arith.add(increasesCoreTimeBalance, curCoreTimeBalance))); // 增值后余额
            hpcAccountIncreases.add(hpcAccountIncrease);
        }

        this.saveBatch(hpcAccountIncreases);
    }
}



